﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Loki;
using Luna.Data.Accounting;

namespace Luna.Model.Accounting
{
    internal class Account : LunaEntity, IAccountData, IEditableAccount
    {
        #region Properties

        #region  Name
        private static PropertyChangedEventArgs _NameChangeArgs = ObservableHelper.CreateArgs<Account>(x => x.Name);

        private string _Name;

        public string Name
        {
            get
            {
                return _Name;
            }

            set
            {
                if (value != _Name)
                {
                    _Name = value;
                    NotifyChangedAndDirty(_NameChangeArgs);
                }
            }
        }
        #endregion

        #region  Bank
        private static PropertyChangedEventArgs _BankChangeArgs = ObservableHelper.CreateArgs<Account>(x => x.Bank);

        private string _Bank;

        public string Bank
        {
            get
            {
                return _Bank;
            }

            set
            {
                if (value != _Bank)
                {
                    _Bank = value;
                    NotifyChanged(_BankChangeArgs);
                }
            }
        }
        #endregion

        #region  Number
        private static PropertyChangedEventArgs _NumberChangeArgs = ObservableHelper.CreateArgs<Account>(x => x.Number);

        private string _Number;

        public string Number
        {
            get
            {
                return _Number;
            }

            set
            {
                if (value != _Number)
                {
                    _Number = value;
                    NotifyChangedAndDirty(_NumberChangeArgs);
                }
            }
        }
        #endregion

        #region  StartDate
        private static PropertyChangedEventArgs _StartDateChangeArgs = ObservableHelper.CreateArgs<Account>(x => x.StartDate);

        private DateTime _StartDate;

        public DateTime StartDate
        {
            get
            {
                return _StartDate;
            }

            set
            {
                if (value != _StartDate)
                {
                    _StartDate = value;
                    NotifyChangedAndDirty(_StartDateChangeArgs);
                }
            }
        }
        #endregion

        #region  InitialAmount
        private static PropertyChangedEventArgs _InitialAmountChangeArgs = ObservableHelper.CreateArgs<Account>(x => x.InitialAmount);

        private decimal _InitialAmount;

        public decimal InitialAmount
        {
            get
            {
                return _InitialAmount;
            }

            set
            {
                if (value != _InitialAmount)
                {
                    _InitialAmount = value;
                    NotifyChangedAndDirty(_InitialAmountChangeArgs);
                }
            }
        }
        #endregion

        #region  ValidatedDate
        private static PropertyChangedEventArgs _ValidatedDateChangeArgs = ObservableHelper.CreateArgs<Account>(x => x.ValidatedDate);

        private DateTime _ValidatedDate;

        public DateTime ValidatedDate
        {
            get
            {
                return _ValidatedDate;
            }

            set
            {
                if (value != _ValidatedDate)
                {
                    _ValidatedDate = value;
                    NotifyChangedAndDirty(_ValidatedDateChangeArgs);
                }
            }
        }
        #endregion

        #region  ValidatedAmount
        private static PropertyChangedEventArgs _ValidatedAmountChangeArgs = ObservableHelper.CreateArgs<Account>(x => x.ValidatedAmount);

        private decimal _ValidatedAmount;

        public decimal ValidatedAmount
        {
            get
            {
                return _ValidatedAmount;
            }

            set
            {
                if (value != _ValidatedAmount)
                {
                    _ValidatedAmount = value;
                    NotifyChangedAndDirty(_ValidatedAmountChangeArgs);
                }
            }
        }
        #endregion

        #region  CurrentAmount
        private static PropertyChangedEventArgs _CurrentAmountChangeArgs = ObservableHelper.CreateArgs<Account>(x => x.CurrentAmount);

        private decimal _CurrentAmount;

        public decimal CurrentAmount
        {
            get
            {
                return _CurrentAmount;
            }

            set
            {
                if (value != _CurrentAmount)
                {
                    _CurrentAmount = value;
                    NotifyChangedAndDirty(_CurrentAmountChangeArgs);
                }
            }
        }
        #endregion

        public Guid PK
        {
            get { return this.ID; }
            set { ID = value; }
        }
        #endregion

        private static readonly string ACCOUNT_INDEX = ExpressionHelper.Reflect<AccountOperation>.GetProperty(x => x.AccountID).Name;

        private LokiCollection<IAccountOperation> _Operations;

        public IEnumerable<IAccountOperation> Operations
        {
            get
            {
                if (_Operations == null)
                {
                    return ApplicationModel.Accounting.Operations[ACCOUNT_INDEX, this.ID];
                }
                else
                {
                    return _Operations;
                }
            }
        }

        public IEditableAccount EditableVersion
        {
            get
            {
                return new Account(this);
            }
        }

        public void AddOperation(IAccountOperation P_Operation)
        {
            AccountOperation L_Operation = P_Operation as AccountOperation;
            if (L_Operation != null)
            {
                L_Operation.Account = this;
                _Operations.Add(L_Operation);
            }
        }

        public void RemoveOperation(IAccountOperation P_Operation)
        {
            IAccountOperation L_OldOperation = _Operations.FirstOrDefault(x => x.ID == P_Operation.ID);
            if (L_OldOperation != null)
            {
                _Operations.Remove(L_OldOperation);
            }
        }

        internal Account()
        {
            _InitialAmount = 0;
            _StartDate = DateTime.Today;

            _Operations = CreateTrackedCollection<IAccountOperation>();
        }

        internal Account(Account P_User)
            : base((LunaEntity)P_User)
        {
            CopyValues(P_User);
            _Operations = CreateTrackedCollection<IAccountOperation>();
            _Operations.BeginInit();
            foreach (IAccountOperation L_Operation in P_User.Operations)
            {
                _Operations.Add(new AccountOperation(L_Operation, this));
            }

            _Operations.EndInit();
            AcceptChanges();
        }

        internal Account(IAccountData P_UserData)
            : base(P_UserData)
        {
            LoadData(P_UserData);
            AcceptChanges();
        }

        public void CopyValues(IAccount P_Clone)
        {
            Name = P_Clone.Name;
            Bank = P_Clone.Bank;
            Number = P_Clone.Number;
            InitialAmount = P_Clone.InitialAmount;
            ValidatedAmount = P_Clone.ValidatedAmount;
            StartDate = P_Clone.StartDate;
            ValidatedDate = P_Clone.ValidatedDate;
            CurrentAmount = P_Clone.CurrentAmount;
        }

        private void LoadData(IAccountData P_Data)
        {
            _Name = P_Data.Name;
            _Bank = P_Data.Bank;
            _Number = P_Data.Number;
            _InitialAmount = P_Data.InitialAmount;
            _StartDate = P_Data.StartDate;
        }
    }
}
